package org.processmining.plugins.complianceframework.visualization;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import org.processmining.contexts.uitopia.UIPluginContext;
import org.processmining.contexts.uitopia.annotations.UITopiaVariant;
import org.processmining.contexts.uitopia.annotations.Visualizer;
import org.processmining.framework.plugin.annotations.Plugin;
import org.processmining.framework.util.ui.widgets.ProMCheckBoxWithPanel;
import org.processmining.framework.util.ui.widgets.ProMCheckBoxWithTextField;
import org.processmining.framework.util.ui.widgets.ProMScrollablePanel;
import org.processmining.framework.util.ui.widgets.ProMSplitPane;
import org.processmining.framework.util.ui.widgets.ProMTable;
import org.processmining.framework.util.ui.widgets.WidgetColors;
import org.processmining.plugins.complianceframework.ComplianceDashboard;
import org.processmining.plugins.DataConformance.Alignment;
import org.processmining.plugins.DataConformance.framework.ExecutionStep;
import org.processmining.plugins.DataConformance.visualization.DataAwareStepTypes;

import com.fluxicon.slickerbox.components.SlickerTabbedPane;
import com.fluxicon.slickerbox.factory.SlickerFactory;
import com.fluxicon.slickerbox.ui.SlickerScrollBarUI;

public class DashboardVisualizer {
	private Map<String, Object> hiddenColumns;
	public ProMTable table;
	private boolean showCaseFrequency;

	// ProMSplitPane tableSplitPane;
	// ProMSplitPane outerSplitPane;

	public DashboardVisualizer() {
		hiddenColumns = new HashMap<String, Object>();
		showCaseFrequency = false;
	}

	@Plugin(name = "Dashboard Visualizer", returnLabels = { "Dashboard visualization" }, returnTypes = { JComponent.class }, parameterLabels = { "Compliance Dashboard" }, help = "Visualize Compliance Dashboard", userAccessible = true)
	@UITopiaVariant(affiliation = UITopiaVariant.EHV, author = "V. Gromov", email = "v.gromov@student.tue.nl")
	@Visualizer(name = "Dashboard Visualizer")
	public JComponent testVis(UIPluginContext context,
			final ComplianceDashboard dashboard) {

		// setup controls & container
		JTabbedPane tabbedPane = new JTabbedPane();
		
		
		final ProMSplitPane outerSplitPane = new ProMSplitPane(
				ProMSplitPane.VERTICAL_SPLIT);
		final ProMSplitPane tableSplitPane = new ProMSplitPane(
				ProMSplitPane.HORIZONTAL_SPLIT);
		DasboardJTree tree = new DasboardJTree(dashboard.getStatementTreeModel());
		JScrollPane scroll = createScrollPane(tree);
		
		tabbedPane.addTab("Visualisation", outerSplitPane);
		tabbedPane.addTab("Statements", scroll);
		
		JPanel columnsControlPanel = SlickerFactory.instance()
				.createRoundedPanel();
		columnsControlPanel.setLayout(new BoxLayout(columnsControlPanel,
				BoxLayout.PAGE_AXIS));

		Set<String> visModeSet = new HashSet<String>(dashboard
				.getAttributeMovesMap().keySet());
		visModeSet.add("Activity");
		final JComboBox visModeComboBox = SlickerFactory.instance()
				.createComboBox(visModeSet.toArray());
		columnsControlPanel.add(visModeComboBox);

		JCheckBox caseFreqCheckBox = SlickerFactory.instance().createCheckBox(
				"Show case frequency", this.showCaseFrequency);
		columnsControlPanel.add(caseFreqCheckBox);

		// setup table
		this.table = new ProMTable(
				new DashboardTableModel(dashboard, visModeComboBox.getItemAt(0)
						.toString(), this.showCaseFrequency));
		DashboardTableCellRenderer cellRenderer = new DashboardTableCellRenderer(
				this.table.getTable(), dashboard);
		this.table.getTable().setDefaultRenderer(Object.class, cellRenderer);

		// setup chart
		Iterator<String> iter;
		if (visModeComboBox.getSelectedItem().toString().equals("Activity")) {
			iter = dashboard.getActivityMovesMap().keySet().iterator();
		} else {
			iter = dashboard.getAttributeMovesMap()
					.get(visModeComboBox.getSelectedItem().toString()).keySet()
					.iterator();
		}

		final DashboardGraphPanel graphPanel = new DashboardGraphPanel(
				dashboard, visModeComboBox.getSelectedItem().toString(), iter
						.next().toString(),
				DashboardVisualizer.this.showCaseFrequency);

		caseFreqCheckBox.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent evt) {
				JCheckBox cb = (JCheckBox) evt.getSource();
				DashboardVisualizer.this.showCaseFrequency = cb.isSelected();

				DefaultTableModel model = new DashboardTableModel(dashboard,
						visModeComboBox.getSelectedItem().toString(),
						DashboardVisualizer.this.showCaseFrequency);
				DashboardVisualizer.this.table.getTable().setModel(model);
				((DashboardTableCellRenderer) DashboardVisualizer.this.table
						.getTable().getDefaultRenderer(Object.class)).init(
						DashboardVisualizer.this.table.getTable(), dashboard);
				Iterator<String> iter;
				if (visModeComboBox.getSelectedItem().toString()
						.equals("Activity")) {
					iter = dashboard.getActivityMovesMap().keySet().iterator();
				} else {
					iter = dashboard.getAttributeMovesMap()
							.get(visModeComboBox.getSelectedItem().toString())
							.keySet().iterator();
				}

				if (iter.hasNext()) {
					graphPanel.init(dashboard, visModeComboBox
							.getSelectedItem().toString(), iter.next()
							.toString(),
							DashboardVisualizer.this.showCaseFrequency);
				}
			}
		});

		visModeComboBox.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent evt) {
				DefaultTableModel model = new DashboardTableModel(dashboard,
						visModeComboBox.getSelectedItem().toString(),
						DashboardVisualizer.this.showCaseFrequency);
				DashboardVisualizer.this.table.getTable().setModel(model);
				((DashboardTableCellRenderer) DashboardVisualizer.this.table
						.getTable().getDefaultRenderer(Object.class)).init(
						DashboardVisualizer.this.table.getTable(), dashboard);
				Iterator<String> iter;
				if (visModeComboBox.getSelectedItem().toString()
						.equals("Activity")) {
					iter = dashboard.getActivityMovesMap().keySet().iterator();
				} else {
					iter = dashboard.getAttributeMovesMap()
							.get(visModeComboBox.getSelectedItem().toString())
							.keySet().iterator();
				}

				if (iter.hasNext()) {
					graphPanel.init(dashboard, visModeComboBox
							.getSelectedItem().toString(), iter.next()
							.toString(),
							DashboardVisualizer.this.showCaseFrequency);
				}
			}

		});

		this.table.getTable().addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				JTable table = (JTable) e.getSource();
				int row = table.rowAtPoint(e.getPoint());
				int column = table.getColumnModel().getColumnIndex(visModeComboBox.getSelectedItem().toString());
				
				String value = table.getValueAt(row, column).toString();
				float[] intervals = dashboard.getIntervals().get(
						visModeComboBox.getSelectedItem().toString());
				if (intervals != null) {
					value = value.substring(value.indexOf(";") + 1,
							value.indexOf("]"));
					for (int i = 0; i < intervals.length; i++)
						if (intervals[i] == Float.parseFloat(value)) {
							value = i + "";
						}
				}

				graphPanel.init(dashboard, visModeComboBox.getSelectedItem()
						.toString(), value,
						DashboardVisualizer.this.showCaseFrequency);
			}
		});

		for (int i = 0; i < table.getTable().getColumnCount(); i++) {
			JCheckBox checkBox = SlickerFactory.instance().createCheckBox(
					table.getTable().getColumnName(i), true);
			checkBox.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent evt) {
					JCheckBox cb = (JCheckBox) evt.getSource();
					String columnName = cb.getText();

					if (cb.isSelected()) {
						showColumn(columnName);
					} else {
						hideColumn(columnName);
					}
				}
			});

			columnsControlPanel.add(checkBox);
		}

		tableSplitPane.setLeftComponent(columnsControlPanel);
		tableSplitPane.setRightComponent(table);
		outerSplitPane.setLeftComponent(tableSplitPane);
		outerSplitPane.setRightComponent(graphPanel);

		return tabbedPane;
//		return scroll;
	}

	public void hideColumn(String name) {
		try {
			TableColumnModel tcm = this.table.getTable().getColumnModel();
			int colIndex = tcm.getColumnIndex(name);
			TableColumn column = tcm.getColumn(colIndex);
			if (column != null) {
				hiddenColumns.put(name, column);
				// hiddenColumns.put(":" + name, new Integer(colIndex));
				this.table.getTable().removeColumn(column);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			return;
		}
	}

	public void showColumn(String name) {
		try {
			TableColumn column = (TableColumn) hiddenColumns.get(name);
			// TableColumnModel tcm = this.table.getTable().getColumnModel();
			if (column == null)
				return;
			hiddenColumns.remove(name);
			this.table.getTable().addColumn(column);
		} catch (Exception ex) {
			ex.printStackTrace();
			return;
		}
	}
	
public JScrollPane createScrollPane(JComponent component) {
		
//		ProMScrollablePanel scrollPanel = new ProMScrollablePanel();
		JPanel scrollPanel = new JPanel();
		scrollPanel.setOpaque(false);
		scrollPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		scrollPanel.setLayout(new BorderLayout(10, 10));
		scrollPanel.add(component, BorderLayout.CENTER);
		
		final JScrollPane scrollPane = new JScrollPane(scrollPanel);
//		final JScrollPane scrollPane = new JScrollPane(component);
		scrollPane.setOpaque(false);
		scrollPane.setBackground(WidgetColors.PROPERTIES_BACKGROUND);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.getViewport().setBackground(WidgetColors.PROPERTIES_BACKGROUND);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		JScrollBar vBar = scrollPane.getVerticalScrollBar();
		vBar.setUI(new SlickerScrollBarUI(vBar, new Color(0, 0, 0, 0), new Color(160, 160, 160),
				WidgetColors.COLOR_NON_FOCUS, 4, 12));
		vBar.setOpaque(false);
		vBar.setBackground(WidgetColors.PROPERTIES_BACKGROUND);
		vBar = scrollPane.getHorizontalScrollBar();
		vBar.setUI(new SlickerScrollBarUI(vBar, new Color(0, 0, 0, 0), new Color(160, 160, 160),
				WidgetColors.COLOR_NON_FOCUS, 4, 12));
		vBar.setOpaque(false);
		vBar.setBackground(WidgetColors.PROPERTIES_BACKGROUND);
		
		return scrollPane;
	}
}
